package com.eastedu.template.core.lifrcycle;

import com.eastedu.exception.ServiceException;
import com.eastedu.report.common.event.ReportGenerateEndEvent;
import com.eastedu.template.core.generator.ReportGenerator;
import com.eastedu.template.core.template.ReportTempleProvider;
import com.eastedu.template.exception.ReportGenerateCallback;
import com.eastedu.template.model.ReportDataContainer;
import com.eastedu.template.thread.HandlerSemaphore;
import com.eastedu.template.thread.ThreadExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.lang.NonNull;

import java.io.InputStream;
import java.util.Objects;

/**
 * The type Default report export cycle.
 *
 * @author superman
 */
@Slf4j
public class DefaultReportExportCycle implements ReportExportCycle, ApplicationEventPublisherAware {

    private final ReportGenerator reportGenerator;
    private final ReportTempleProvider reportTempleProvider;
    private ApplicationEventPublisher applicationEventPublisher;

    /**
     * Instantiates a new Default report export cycle.
     *
     * @param reportGenerator      the report generator
     * @param reportTempleProvider the report temple provider
     */
    public DefaultReportExportCycle(ReportGenerator reportGenerator,
                                    ReportTempleProvider reportTempleProvider) {
        this.reportGenerator = reportGenerator;
        this.reportTempleProvider = reportTempleProvider;
    }

    @Override
    public void start(ReportDataContainer container, ReportGenerateCallback callback) {
        String taskId = container.getTaskId();
        String templateCode = container.getTemplateCode();
        ThreadExecutor.execute(() -> {
            try {
                // 该校验仅支持单机部署，如果是集群部署，需要考虑分布式方案
                if (!HandlerSemaphore.isInterrupted(taskId)) {
                    throw new ServiceException("当前报告正在生成中");
                }
                HandlerSemaphore.record(taskId);
                InputStream template = getTemplate(templateCode);
                callback.success(taskId, reportGenerator.generate(container, template));
            } catch (Throwable throwable) {
                log.error("「{}」生成报告失败", taskId, throwable);
                callback.failure(taskId, throwable);
            } finally {
                HandlerSemaphore.remove(taskId);
                applicationEventPublisher.publishEvent(new ReportGenerateEndEvent(taskId));
            }
        }, container.isDebug());

    }

    private InputStream getTemplate(String templateCode) {
        InputStream template = reportTempleProvider.getTemplate(templateCode);
        if (Objects.isNull(template)) {
            throw new ServiceException("未配置模版文件");
        }
        return template;
    }

    @Override
    public void stop(String taskId) {
        HandlerSemaphore.terminate(taskId);
    }

    @Override
    public void setApplicationEventPublisher(@NonNull ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
}
